package com.qfedu.entity.chapter2.course12;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSATest {
    private final static String SIGNATURE_ALGORITHM = "MD5withRSA";

    public static void main(String[] args) throws Exception {
        // 1.获取公钥私钥
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");// 获取RSA算法实例
        keyPairGen.initialize(1024);// 1024代表密钥二进制位数

        KeyPair keyPair = keyPairGen.generateKeyPair();// 产生KeyPair工厂
//        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        byte[] publicKeyBytes = publicKey.getEncoded();
        byte[] privateKeyBytes = privateKey.getEncoded();
        System.out.println("公钥：" + Base64.getEncoder().encodeToString(publicKeyBytes));
        System.out.println("私钥：" + Base64.getEncoder().encodeToString(privateKeyBytes));
        String content = "学习算法，有益身心健康!！";

        Cipher cipher = Cipher.getInstance("RSA");    // 初始化加密器
        // 2.使用私钥加密
        System.out.println("============   私钥加密     ===========");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] encodeContent = cipher.doFinal(content.getBytes());
        System.out.println("私钥加密后的数据：" + Base64.getEncoder().encodeToString(encodeContent));

        // 3.使用公钥解密
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        byte[] decodeContent = cipher.doFinal(encodeContent);
        System.out.println("公钥解密后的数据：" + new String(decodeContent));

        // 4.使用公钥加密
        System.out.println("============   公钥加密     ===========");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encodeContent2 = cipher.doFinal(content.getBytes());
        ;
        System.out.println("公钥加密后的数据：" + Base64.getEncoder().encodeToString(encodeContent2));

        // 5.使用私钥解密
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decodeContent2 = cipher.doFinal(encodeContent2);
        System.out.println("私钥解密后的数据：" + new String(decodeContent2));

        // 6.加签
        System.out.println("============   加签     ===========");
        // 获取签名算法
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(content.getBytes());
        String sign = Base64.getEncoder().encodeToString(signature.sign());
        System.out.println("加签后的数据：" + sign);

        // 7.验签
        signature.initVerify(publicKey);
        signature.update(content.getBytes());
        boolean result = signature.verify(Base64.getDecoder().decode(sign));
        System.out.println("验签结果：" + result);
    }

    /**
     * 使用私钥对数据进行加密
     */
    public static byte[] encryptPrivateKey(byte[] binaryData, byte[] privateKeyBytes) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

        // 获取RSA算法实例
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key priKey = keyFactory.generatePrivate(keySpec);

        // 初始化加密器
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, priKey);
        return cipher.doFinal(binaryData);
    }

    /**
     * 使用公钥对数据进行加密
     */
    public static byte[] encryptPublicKey(byte[] binaryData, byte[] publicKeyBytes) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);

        // 获取RSA算法实例
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key pubKey = keyFactory.generatePublic(keySpec);

        // 初始化加密器
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(binaryData);
    }

    /**
     * 使用私钥对数据进行解密
     */
    public static byte[] decryptPrivateKey(byte[] binaryData, byte[] privateKeyBytes) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

        // 获取RSA算法实例
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key priKey = keyFactory.generatePrivate(keySpec);

        // 初始化加密器
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        return cipher.doFinal(binaryData);
    }

    /**
     * 使用公钥对数据进行解密
     */
    public static byte[] decryptPublicKey(byte[] binaryData, byte[] publicKeyBytes) throws Exception {
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);

        // 获取RSA算法实例
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key pubKey = keyFactory.generatePublic(x509KeySpec);

        // 初始化加密器
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        return cipher.doFinal(binaryData);
    }

    /**
     * 使用私钥对数据进行签名
     */
    public static String sign(byte[] binaryData, byte[] privateKeyBytes)
            throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

        // 获取RSA算法实例
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyFactory.generatePrivate(keySpec);

        // 获取签名算法
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(binaryData);
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    /**
     * 使用公钥对数据签名进行验证
     */
    public static boolean verify(byte[] binaryData, byte[] publicKeyBytes, String sign)
            throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        // 获取RSA算法实例
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        // 获取签名算法
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(binaryData);
        return signature.verify(Base64.getDecoder().decode(sign));
    }

}
